package com.backend.modules.task.service;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.backend.common.ai.DeepseekClient;
import com.backend.common.event.SubmissionCreatedEvent;
import com.backend.common.event.TaskSubmissionEvent;
import com.backend.modules.task.dto.FileAuditResult;
import com.backend.modules.task.entity.Task;
import com.backend.modules.task.entity.TaskSubmission;
import com.backend.modules.task.entity.TaskSubmissionFile;
import com.backend.modules.task.enums.SubmissionStatus;
import com.fasterxml.jackson.databind.ObjectMapper;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * AI审核服务
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AIAuditService {
    
    private final DeepseekClient deepseekClient;
    private final TaskSubmissionService taskSubmissionService;
    private final NotificationService notificationService;
    private final ApplicationEventPublisher eventPublisher;
    private final ObjectMapper objectMapper;
    
    /**
     * 监听任务提交创建事件，触发AI审核流程
     */
    @Async
    @EventListener
    @Transactional
    public void handleSubmissionCreatedEvent(SubmissionCreatedEvent event) {
        TaskSubmission submission = event.getSubmission();
        if (submission == null) {
            log.error("提交记录为空");
            return;
        }
        
        try {
            Task task = submission.getTask();
            List<TaskSubmissionFile> files = submission.getFiles();
            
            // 获取任务要求
            String fileRequirements = task.getFileRequirements();
            String submitRequirements = task.getSubmitRequirements();
            
            // 整合所有文件信息
            String filesInfo = generateFilesInfo(files);
            
            // 生成审核请求
            String systemPrompt = generateSystemPrompt();
            String userPrompt = generateUserPrompt(fileRequirements, submitRequirements, filesInfo);
            
            // 调用AI审核
            String aiResponse = deepseekClient.formatAuditChatCompletion(systemPrompt, userPrompt);
            FileAuditResult auditResult = parseAuditResult(aiResponse);
            
            // 处理审核结果
            processAuditResult(submission, auditResult);
            
        } catch (Exception e) {
            log.error("AI审核失败", e);
            // 审核失败，转入教师审核
            submission.setStatus(SubmissionStatus.TEACHER_REVIEWING.name());
            taskSubmissionService.update(submission);
        }
    }
    
    /**
     * 生成文件信息
     */
    private String generateFilesInfo(List<TaskSubmissionFile> files) {
        StringBuilder sb = new StringBuilder();
        sb.append("提交的文件列表：\n");
        
        for (int i = 0; i < files.size(); i++) {
            TaskSubmissionFile file = files.get(i);
            sb.append(i + 1).append(". 文件名: ").append(file.getFileName())
              .append(", 文件类型: ").append(file.getFileType())
              .append(", 文件大小: ").append(formatFileSize(file.getFileSize()))
              .append("\n");
        }
        
        return sb.toString();
    }
    
    /**
     * 格式化文件大小
     */
    private String formatFileSize(Long size) {
        if (size < 1024) {
            return size + " B";
        } else if (size < 1024 * 1024) {
            return String.format("%.2f KB", size / 1024.0);
        } else if (size < 1024 * 1024 * 1024) {
            return String.format("%.2f MB", size / (1024.0 * 1024));
        } else {
            return String.format("%.2f GB", size / (1024.0 * 1024 * 1024));
        }
    }
    
    /**
     * 生成系统提示词
     */
    private String generateSystemPrompt() {
        return "你是一个专业的文件格式审核助手，负责检查学生提交的文件是否符合要求。你需要严格按照教师提供的文件要求进行审核。\n" +
                "你的职责是：\n" +
                "1. 检查文件名称是否符合规范\n" +
                "2. 检查文件类型是否符合要求\n" +
                "3. 检查文件数量是否符合要求\n" +
                "4. 提供明确的审核结果，并给出具体的问题说明和修改建议\n\n" +
                "【重要规则】：\n" +
                "1. 你必须严格按照教师提供的文件要求和提交要求进行审核，不得添加或发明任何未在要求中明确指定的规则\n" +
                "2. 如果教师没有明确要求文件名必须包含学号、班级等信息，则不应将此作为审核标准\n" +
                "3. 只有在教师明确提出特定命名规则时，才能据此判断文件命名是否规范\n" +
                "4. 如果教师没有提供任何特定要求，仅在明显不合理的情况下（如文件名包含敏感词或特殊字符）才判定为不通过\n\n" +
                "你必须使用中文回复，不允许使用任何其他语言。\n\n" +
                "你需要以JSON格式返回审核结果，包含以下字段：\n" +
                "- passed: 布尔值，表示是否通过审核\n" +
                "- reason: 字符串，未通过的总体原因（必须使用中文）\n" +
                "- suggestions: 字符串数组，具体修改建议（必须使用中文）。每条建议必须明确指出需要修改的具体文件名称，例如'请修改xxx.docx文件的命名格式'\n" +
                "- issues: 问题数组，每个问题包含type(问题类型)、description(问题描述，必须使用中文)、severity(严重程度)、fileName(问题相关的文件名)\n\n" +
                "在suggestions中，你需要对文件列表的增删改查操作进行分类描述：\n" +
                "1. 增加文件：明确指出需要增加哪些文件，例如'请增加xxx.docx文件'\n" +
                "2. 删除文件：明确指出需要删除哪些文件，例如'请删除xxx.docx文件'\n" +
                "3. 修改文件：明确指出需要修改哪些文件，例如'请修改xxx.docx文件的命名格式'\n" +
                "4. 查询文件：明确指出需要查询哪些文件，例如'请查询xxx.docx文件是否存在'\n\n" +
                "每个建议必须指出不符合的具体规定，例如'请修改xxx.docx文件的命名格式，不符合规定：文件命名必须使用英文'。如果没有明确规定，则不应添加不符合规定部分。";
    }
    
    /**
     * 生成用户提示词
     */
    private String generateUserPrompt(String fileRequirements, String submitRequirements, String filesInfo) {
        StringBuilder sb = new StringBuilder();
        sb.append("请审核以下学生提交的文件是否符合要求：\n\n");
        
        sb.append("## 文件要求\n");
        if (fileRequirements != null && !fileRequirements.trim().isEmpty()) {
            sb.append(fileRequirements).append("\n\n");
        } else {
            sb.append("教师未提供特定的文件要求。\n\n");
        }
        
        sb.append("## 提交要求\n");
        if (submitRequirements != null && !submitRequirements.trim().isEmpty()) {
            sb.append(submitRequirements).append("\n\n");
        } else {
            sb.append("教师未提供特定的提交要求。\n\n");
        }
        
        sb.append("## 提交文件信息\n");
        sb.append(filesInfo).append("\n");
        
        sb.append("请根据上述信息，严格审核学生提交的文件是否符合要求，并以JSON格式返回审核结果。\n");
        sb.append("请记住，你只能根据教师明确提供的文件要求和提交要求进行审核，不要添加任何未在要求中明确指定的规则。\n");
        sb.append("如果教师没有明确要求文件名必须包含学号、班级等信息，则不应将此作为审核标准。\n");
        sb.append("必须使用中文回答，所有文字内容必须是中文。\n");
        sb.append("在提出修改建议时，必须明确指出需要修改的具体文件名称。");
        
        return sb.toString();
    }
    
    /**
     * 解析审核结果
     */
    private FileAuditResult parseAuditResult(String aiResponse) throws IOException {
        try {
            return objectMapper.readValue(aiResponse, FileAuditResult.class);
        } catch (Exception e) {
            log.error("解析AI审核结果失败: {}", aiResponse, e);
            throw e;
        }
    }
    
    /**
     * 处理审核结果
     */
    private void processAuditResult(TaskSubmission submission, FileAuditResult auditResult) {
        if (auditResult.isPassed()) {
            // 通过AI审核，转入教师审核
            submission.setStatus(SubmissionStatus.TEACHER_REVIEWING.name());
            // 设置空审核意见
            submission.setReviewComment("");
            taskSubmissionService.update(submission);
            
            // 不需要发送邮件通知，由教师审核后再通知
        } else {
            // 未通过AI审核
            submission.setStatus(SubmissionStatus.REJECTED.name());
            
            // 生成审核意见
            String reviewComment = generateReviewComment(auditResult);
            submission.setReviewComment(reviewComment);
            submission.setReviewTime(LocalDateTime.now());
            
            taskSubmissionService.update(submission);
            
            // 发送通知给学生
            notificationService.sendAIRejectionNotification(submission, auditResult);
        }
    }
    
    /**
     * 生成审核意见
     */
    private String generateReviewComment(FileAuditResult auditResult) {
        StringBuilder sb = new StringBuilder();
        
        // 添加总体审核结果
        sb.append("【审核结果】").append("\n");
        sb.append(auditResult.getReason()).append("\n\n");
        
        // 按文件名分组整理问题
        Map<String, List<FileAuditResult.FileIssue>> fileIssuesMap = new HashMap<>();
        if (auditResult.getIssues() != null && !auditResult.getIssues().isEmpty()) {
            // 按文件名分组
            for (FileAuditResult.FileIssue issue : auditResult.getIssues()) {
                String fileName = issue.getFileName() != null ? issue.getFileName() : "未指定";
                fileIssuesMap.computeIfAbsent(fileName, k -> new ArrayList<>()).add(issue);
            }
            
            // 输出每个文件的问题
            sb.append("【问题详情】").append("\n");
            for (Map.Entry<String, List<FileAuditResult.FileIssue>> entry : fileIssuesMap.entrySet()) {
                String fileName = entry.getKey();
                List<FileAuditResult.FileIssue> issues = entry.getValue();
                
                sb.append("文件：").append(fileName).append("\n");
                for (FileAuditResult.FileIssue issue : issues) {
                    sb.append("  - ").append(issue.getDescription())
                      .append(" (").append(translateSeverity(issue.getSeverity())).append(")")
                      .append("\n");
                }
                sb.append("\n");
            }
        }
        
        // 输出修改建议，按增删改查分类
        if (auditResult.getSuggestions() != null && !auditResult.getSuggestions().isEmpty()) {
            sb.append("【修改建议】").append("\n");
            
            // 分类存储不同类型的建议
            List<String> addSuggestions = new ArrayList<>();
            List<String> deleteSuggestions = new ArrayList<>();
            List<String> modifySuggestions = new ArrayList<>();
            List<String> querySuggestions = new ArrayList<>();
            
            // 对建议进行分类
            for (String suggestion : auditResult.getSuggestions()) {
                if (suggestion.contains("增加") || suggestion.contains("添加")) {
                    addSuggestions.add(suggestion);
                } else if (suggestion.contains("删除") || suggestion.contains("移除")) {
                    deleteSuggestions.add(suggestion);
                } else if (suggestion.contains("修改") || suggestion.contains("更改")) {
                    modifySuggestions.add(suggestion);
                } else if (suggestion.contains("查询") || suggestion.contains("检查")) {
                    querySuggestions.add(suggestion);
                } else {
                    // 默认归类为修改建议
                    modifySuggestions.add(suggestion);
                }
            }
            
            // 输出增加文件的建议
            if (!addSuggestions.isEmpty()) {
                sb.append("需要增加的文件：\n");
                for (String suggestion : addSuggestions) {
                    sb.append("- ").append(suggestion).append("\n");
                }
                sb.append("\n");
            }
            
            // 输出删除文件的建议
            if (!deleteSuggestions.isEmpty()) {
                sb.append("需要删除的文件：\n");
                for (String suggestion : deleteSuggestions) {
                    sb.append("- ").append(suggestion).append("\n");
                }
                sb.append("\n");
            }
            
            // 输出修改文件的建议
            if (!modifySuggestions.isEmpty()) {
                sb.append("需要修改的文件：\n");
                for (String suggestion : modifySuggestions) {
                    sb.append("- ").append(suggestion).append("\n");
                }
                sb.append("\n");
            }
            
            // 输出查询文件的建议
            if (!querySuggestions.isEmpty()) {
                sb.append("需要查询的文件：\n");
                for (String suggestion : querySuggestions) {
                    sb.append("- ").append(suggestion).append("\n");
                }
                sb.append("\n");
            }
        }
        
        return sb.toString();
    }
    
    /**
     * 翻译严重程度
     */
    private String translateSeverity(String severity) {
        if (severity == null) {
            return "一般";
        }
        
        switch (severity.toLowerCase()) {
            case "error":
                return "严重";
            case "warning":
                return "警告";
            case "info":
                return "提示";
            default:
                return severity;
        }
    }
} 